﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using vJine.Core.Task;
using System.IO;
using System.Reflection;
using System.Collections;

namespace vJine.Core.Log {
    /// <summary>
    /// 日志帮助类
    /// </summary>
    public class LogManager : IDisposable {
        /// <summary>
        /// 日志文件保存目录
        /// </summary>
        public string log_dir { get; private set; }
        /// <summary>
        /// 日志文件名称前缀
        /// </summary>
        public string name_prefix { get; private set; }
        /// <summary>
        /// 最大日志行数
        /// </summary>
        public int log_max { get; private set; }
        TaskQueue<string> log_pipe = null;
        /// <summary>
        /// 实例化日志帮助类
        /// </summary>
        /// <param name="log_dir">日志文件保存目录</param>
        /// <param name="log_max">最大日志行数</param>
        /// <param name="name_prefix">日志文件名称前缀</param>
        public LogManager(string log_dir, int log_max, string name_prefix = "") {
            this.name_prefix =
                string.IsNullOrEmpty(name_prefix) ? "" : name_prefix;

            if (!Directory.Exists(log_dir)) {
                Directory.CreateDirectory(log_dir);
            }

            this.log_dir = log_dir;
            this.log_max = log_max;

            this.log_pipe =
                new TaskQueue<string>(1000, this.log_writer);
            this.log_pipe.Start();
        }

        Stream logStream = null; StreamWriter logWriter = null;
        int log_file_counter = 0, log_counter = 0;
        DateTime log_start = DateTime.Now;
        void log_writer(string log) {
            string log_file = "";

        next_log: ;
            if (logWriter == null) {
                goto get_log_file;
            }
            if (this.log_counter > this.log_max) {
                this.log_counter = 0;
                goto get_log_file;
            }
            if (DateTime.Now.AddDays(-1) > log_start) {
                goto get_log_file;
            }

            logWriter.WriteLine(log); logWriter.Flush();

            this.log_counter += 1;

            return;
        get_log_file: ;
            if (this.logWriter != null) {
                this.logWriter.Close();
                this.logWriter = null; this.logStream = null;
            }

            this.log_start = DateTime.Now;
            for (int i = 0; ; i++) {
                log_file =
                    Path.Combine(this.log_dir, string.Format("{0}{1:yyMMdd}_{2:000}.log", this.name_prefix, this.log_start, i));
                if (!File.Exists(log_file)) {
                    log_file_counter = i;
                    break;
                }
            }

            this.logStream =
                new FileStream(log_file, FileMode.CreateNew, FileAccess.Write, FileShare.Read);
            this.logWriter = new StreamWriter(this.logStream);

            goto next_log;
        }
        /// <summary>
        /// 新增消息日志
        /// </summary>
        /// <param name="info">消息</param>
        public void I(params string[] info) {
            this.log_pipe.Enqueue("[I]," + string.Join(",", info));
        }
        /// <summary>
        /// 新增警告日志
        /// </summary>
        /// <param name="warning">警告</param>
        public void W(params string[] warning) {
            this.log_pipe.Enqueue("[W]," + string.Join(",", warning));
        }
        /// <summary>
        /// 新增错误日志
        /// </summary>
        /// <param name="error">错误</param>
        public void E(params string[] error) {
            this.log_pipe.Enqueue("[E]," + string.Join(",", error));
        }
        /// <summary>
        /// 新增错误日志
        /// </summary>
        /// <param name="tag">错误标记</param>
        /// <param name="ex">错误</param>
        public void E(string tag, Exception ex) {
            this.log_pipe.Enqueue("[E], " + LogManager.dump("***", ex));
        }
        /// <summary>
        /// 新增失败日志
        /// </summary>
        /// <param name="fatal"></param>
        public void F(params string[] fatal) {
            this.log_pipe.Enqueue("[F]," + string.Join(",", fatal));
        }
        /// <summary>
        /// 释放日志资源
        /// </summary>
        public void Dispose() {
            this.log_pipe.Stop();

            if (this.logWriter != null) {
                this.logWriter.Flush();
                this.logWriter.Close();
                this.logWriter = null; this.logStream = null;
            }
        }

        #region Helper
        /// <summary>
        /// 枚举错误
        /// </summary>
        /// <param name="m">导致错误的方法</param>
        /// <returns>错误信息</returns>
        public static string dump(MethodInfo m) {
            ParameterInfo[] P = m.GetParameters();
            StringBuilder sbM = new StringBuilder();
            sbM.AppendFormat("Name:{0},Params:[{1}]" + Environment.NewLine, m.Name, P.Length);
            for(int i = 0, len = P.Length; i < len; i++) {
                ParameterInfo p = P[i];
                sbM.AppendFormat("P[{0}],Name:{1},Type:{2}" + Environment.NewLine, i, p.Name, p.ParameterType.FullName);
            }

            return sbM.ToString();
        }
        /// <summary>
        /// 枚举错误
        /// </summary>
        /// <param name="Tag">错误标记</param>
        /// <param name="ex">错误</param>
        /// <returns>错误信息</returns>
        public static string dump(string Tag, Exception ex) {
            StringBuilder sbEx = new StringBuilder(2000);
            dump(Tag, sbEx, ex); return sbEx.ToString();
        }

        static void dump(string Tag, StringBuilder sbEx, Exception ex) {
            sbEx.Append("=============" + Tag + "=============" + Environment.NewLine);
            sbEx.AppendFormat("Message:{0}" + Environment.NewLine, ex.Message);

            sbEx.AppendFormat("Data:" + Environment.NewLine);
            foreach (DictionaryEntry de in ex.Data) {
                sbEx.AppendFormat("Key:{0},Value:{1}" + Environment.NewLine, de.Key.ToString(), de.Value.ToString());
            }

            sbEx.AppendFormat("Help Link:{0}" + Environment.NewLine, ex.HelpLink);

            sbEx.AppendFormat("Source:{0}" + Environment.NewLine, ex.Source);
            sbEx.AppendFormat("StackTrace:" + Environment.NewLine + "{0}" + Environment.NewLine, ex.StackTrace);
            if (ex.TargetSite != null) {
                sbEx.AppendFormat("TargetSite:{0}@{1}" + Environment.NewLine, ex.TargetSite.Name, ex.TargetSite.DeclaringType.ToString());
            }

            if (ex.InnerException != null) {
                dump(Tag, sbEx, ex.InnerException);
            }
        }
        #endregion
    }
}
